home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1993 / MacHack 1993.toast / MacHack™ 1987-1992 / MacHack™ '90 / Source Code ƒ / MPW C ƒ / xbinƒ / xbin.c next >
Encoding:
C/C++ Source or Header  |  1989-10-15  |  20.9 KB  |  1,067 lines  |  [TEXT/MPS ]

  1. /*
  2. # Build an MPW tool
  3. C -d MPW xbin.c
  4. Link -w -o xbin -t MPST -c "MPS " xbin.c.o ∂
  5.     "{CLibraries}"CRuntime.o ∂
  6.     "{CLibraries}"StdCLib.o ∂
  7.     "{CLibraries}"CInterface.o ∂
  8.     "{Libraries}"ToolLibs.o ∂
  9.     "{Libraries}"Interface.o 
  10. */
  11. #ifndef lint
  12. static char version[] = "xbin.c Version 3.0 09/30/89";
  13. #endif lint
  14. #include <stdio.h>
  15. #include <errno.h>
  16.  
  17. #ifndef    MPW
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <sys/dir.h>
  21. #else    MPW
  22. #include <Types.h>
  23. #include <Files.h>
  24. #include <Memory.h>
  25. #include <ErrMgr.h>
  26. #include <StdLib.h>
  27. #include <String.h>
  28. #include <CursorCtl.h>
  29. #define     FALSE 0
  30. #define     TRUE 1
  31. /* stops linker linking these in */
  32. ecvt() {}
  33. fcvt() {}
  34. #endif    MPW
  35. extern int errno;
  36.  
  37. #ifdef MAXNAMLEN    /* 4.2 BSD */
  38. #define FNAMELEN MAXNAMLEN
  39. #else
  40. #define FNAMELEN DIRSIZ
  41. #endif
  42.  
  43. #ifdef BSD
  44. #include <sys/time.h>
  45. #include <sys/timeb.h>
  46. #define search_last rindex
  47. extern char *rindex();
  48. #else
  49. #include <time.h>
  50. extern long timezone;
  51. #define search_last strrchr
  52. extern char *strrchr();
  53. #endif
  54.  
  55. /* Mac time of 00:00:00 GMT, Jan 1, 1970 */
  56. #define TIMEDIFF 0x7c25b080
  57.  
  58. #define DATABYTES 128
  59.  
  60. #define BYTEMASK 0xff
  61. #define BYTEBIT 0x100
  62. #define WORDMASK 0xffff
  63. #define WORDBIT 0x10000
  64.  
  65. #define NAMEBYTES 63
  66. #define H_NLENOFF 1
  67. #define H_NAMEOFF 2
  68.  
  69. /* 65 <-> 80 is the FInfo structure */
  70. #define H_TYPEOFF 65
  71. #define H_AUTHOFF 69
  72. #define H_FLAGOFF 73
  73.  
  74. #define H_LOCKOFF 81
  75. #define H_DLENOFF 83
  76. #define H_RLENOFF 87
  77. #define H_CTIMOFF 91
  78. #define H_MTIMOFF 95
  79.  
  80. #define H_OLD_DLENOFF 81
  81. #define H_OLD_RLENOFF 85
  82.  
  83. #define F_BUNDLE 0x2000
  84. #define F_LOCKED 0x8000
  85.  
  86. struct macheader {
  87.     char m_name[NAMEBYTES+1];
  88.     char m_type[4];
  89.     char m_author[4];
  90.     short m_flags;
  91.     long m_datalen;
  92.     long m_rsrclen;
  93.     long m_createtime;
  94.     long m_modifytime;
  95. } mh;
  96.  
  97. struct filenames {
  98.     char f_info[256];
  99.     char f_data[256];
  100.     char f_rsrc[256];
  101. } files;
  102.  
  103. int pre_beta;    /* options */
  104. int listmode;
  105. int verbose;
  106.  
  107. int compressed;    /* state variables */
  108. int qformat;
  109. FILE *ifp;
  110. long get4q();
  111.  
  112. /*
  113.  * xbin -- unpack BinHex format file into suitable
  114.  * format for downloading with macput
  115.  * Dave Johnson, Brown University Computer Science
  116.  *
  117.  * (c) 1984 Brown University
  118.  * may be used but not sold without permission
  119.  *
  120.  * created ddj 12/16/84
  121.  * revised ddj 03/10/85 -- version 4.0 compatibility, other minor mods
  122.  * revised ddj 03/11/85 -- strip LOCKED bit from m_flags
  123.  * revised ahm 03/12/85 -- System V compatibility
  124.  * revised dba 03/16/85 -- (Darin Adler, TMQ Software)  4.0 EOF fixed,
  125.  *               4.0 checksum added
  126.  * revised ddj 03/17/85 -- extend new features to older formats: -l, stdin
  127.  * revised ddj 03/24/85 -- check for filename truncation, allow multiple files
  128.  * revised ddj 03/26/85 -- fixed USG botches, many problems w/multiple files
  129.  * revised jcb 03/30/85 -- (Jim Budler, amdcad!jimb), revised for compatibility
  130.  *               with 16-bit int machines
  131.  * revised dl  06/16/85 -- (Dan LaLiberte, liberte@uiucdcs) character
  132.  *               translation speedup
  133.  * revised ddj 09/30/85 -- fixed problem with run of RUNCHAR
  134.  * revised sw  09/30/89 -- much hacked about to work with MPW
  135.  */
  136. char usage[] = "usage: \"xbin [-v] [-l] [-o] [-n name] [-] filename\"\n";
  137.  
  138. main(ac, av)
  139. char **av;
  140. {
  141.     char *filename, *macname;
  142.  
  143. #ifdef    MPW
  144.     InitCursorCtl(nil);
  145. #endif    MPW
  146.     filename = ""; macname = "";
  147.     ac--; av++;
  148.     while (ac) {
  149.         if (av[0][0] == '-') {
  150.             switch (av[0][1]) {
  151.             case '\0':
  152.                 filename = "-";
  153.                 break;
  154.             case 'v':
  155.                 verbose++;
  156.                 break;
  157.             case 'l':
  158.                 listmode++;
  159.                 break;
  160.             case 'o':
  161.                 pre_beta++;
  162.                 break;
  163.             case 'n':
  164.                 if (ac > 1) {
  165.                     ac--; av++;
  166.                     macname = av[0];
  167.                     filename = "";
  168.                     break;
  169.                 }
  170.                 else
  171.                     goto bad_usage;
  172.             default:
  173.                 goto bad_usage;
  174.             }
  175.         }
  176.         else
  177.             filename = av[0];
  178.         if (filename[0] != '\0') {
  179.             setup_files(filename, macname);
  180.             if (listmode) {
  181.                 print_header();
  182.             }
  183.             else {
  184.                 process_forks();
  185.                 /* now that we know the size of the forks */
  186.                 forge_info();
  187.             }
  188.             if (ifp != stdin)
  189.                 fclose(ifp);
  190.             macname = "";
  191.             ifp = NULL;        /* reset state */
  192.             qformat = 0;
  193.             compressed = 0;
  194.         }
  195.         ac--; av++;
  196.     }
  197.     if (*filename == '\0') {
  198. bad_usage:
  199.         fprintf(stderr, usage);
  200.         exit(1);
  201.     }
  202. }
  203.  
  204. static char *extensions[] = {
  205.     ".hqx",
  206.     ".hcx",
  207.     ".hex",
  208.     "",
  209.     NULL
  210. };
  211.  
  212. setup_files(filename, macname)
  213. char *filename;        /* input file name -- extension optional */
  214. char *macname;        /* name to use on the mac side of things */
  215. {
  216.     char **ep;
  217.     char namebuf[256];
  218. #ifndef    MPW
  219.     int n;
  220.     char *np;
  221.     struct stat stbuf;
  222. #else    MPW
  223.     FInfo    finderInfo;
  224. #endif    MPW
  225.     long curtime;
  226. #ifdef    MPW
  227.     OSType    f_creator, f_type;
  228. #endif    MPW
  229.  
  230.     if (filename[0] == '-') {
  231.         ifp = stdin;
  232. #ifdef    MPW
  233.         filename = "Dev:Stdin";
  234. #else    MPW
  235.         filename = "stdin";
  236. #endif    MPW
  237.         strcpy (namebuf, filename);
  238.     }
  239.     else {
  240.         /* find input file and open it */
  241.         for (ep = extensions; *ep != NULL; ep++) {
  242.             sprintf(namebuf, "%s%s", filename, *ep);
  243. #ifndef    MPW
  244.             if (stat(namebuf, &stbuf) == 0)
  245.                 break;
  246. #else    MPW
  247.             c2pstr(namebuf);
  248.             if (GetFInfo (namebuf, 0, &finderInfo) == noErr) {
  249.                 p2cstr(namebuf);
  250.                 break;
  251.             }
  252.             p2cstr(namebuf);
  253. #endif    MPW
  254.         }
  255.         if (*ep == NULL) {
  256.             perror(namebuf);
  257.             exit(-1);
  258.         }
  259.         ifp = fopen(namebuf, "r");
  260.         if (ifp == NULL) {
  261.             perror(namebuf);
  262.             exit(-1);
  263.         }
  264.     }
  265.     if (ifp == stdin) {
  266.         curtime = time(0);
  267.         mh.m_createtime = curtime;
  268.         mh.m_modifytime = curtime;
  269.     }
  270.     else {
  271. #ifndef    MPW
  272.         mh.m_createtime = stbuf.st_mtime;
  273.         mh.m_modifytime = stbuf.st_mtime;
  274. #endif    MPW
  275.     }
  276.     if (listmode || verbose) {
  277.         fprintf(stderr, "%s %s%s",
  278.             listmode ? "Listing" : "Converting",
  279.             namebuf, listmode ? ":\n" : " ");
  280.     }
  281.     qformat = find_header(); /* eat mailer header &cetera, intuit format */
  282.  
  283.     if (qformat)
  284.         do_q_header(macname);
  285.     else
  286.         do_o_header(macname, filename);
  287.  
  288. #ifndef    MPW
  289.     /* make sure host file name doesn't get truncated beyond recognition */
  290.     n = strlen(mh.m_name);
  291.     if (n > FNAMELEN - 2)
  292.         n = FNAMELEN - 2;
  293.     strncpy(namebuf, mh.m_name, n);
  294.     namebuf[n] = '\0';
  295.     /* get rid of troublesome characters */
  296.     for (np = namebuf; *np; np++)
  297.         if (*np <= ' ' || *np == '/' || *np >= '\177')
  298.             *np = '_';
  299.  
  300.     sprintf(files.f_data, "%s.data", namebuf);
  301.     sprintf(files.f_rsrc, "%s.rsrc", namebuf);
  302.     sprintf(files.f_info, "%s.info", namebuf);
  303.     if (verbose)
  304.         fprintf(stderr, "==> %s.{info,data,rsrc}\n", namebuf);
  305. #else    MPW
  306.     if (verbose)
  307.         fprintf(stderr, "==> \"%s\"\n", mh.m_name);
  308.     BlockMove (mh.m_author, (char *)&f_creator, 4);
  309.     BlockMove (mh.m_type, (char *)&f_type, 4);
  310.     c2pstr(mh.m_name);
  311.     (void)Create (mh.m_name, 0, f_creator, f_type);
  312.     p2cstr(mh.m_name);
  313. #endif    MPW
  314. }
  315.  
  316. /* print out header information in human-readable format */
  317. print_header()
  318. {
  319.     char *ctime();
  320.  
  321.     printf("macname: %s\n", mh.m_name);
  322.     printf("filetype: %.4s, ", mh.m_type);
  323.     printf("author: %.4s, ", mh.m_author);
  324.     printf("flags: 0x%x\n", mh.m_flags);
  325.     if (qformat) {
  326.         printf("data length: %ld, ", mh.m_datalen);
  327.         printf("rsrc length: %ld\n", mh.m_rsrclen);
  328.     }
  329.     if (!pre_beta) {
  330.         printf("create time: %s", ctime(&mh.m_createtime));
  331.     }
  332. }
  333.  
  334. process_forks()
  335. {
  336.     if (qformat) {
  337.         /* read data and resource forks of .hqx file */
  338. #ifdef    MPW
  339.         do_q_fork(mh.m_name, mh.m_datalen, TRUE);
  340.         do_q_fork(mh.m_name, mh.m_rsrclen, FALSE);
  341. #else    MPW
  342.         if (mh.m_datalen > 0)
  343.             do_q_fork(files.f_data, mh.m_datalen, TRUE);
  344.         if (mh.m_rsrclen > 0)
  345.             do_q_fork(files.f_rsrc, mh.m_rsrclen, FALSE);
  346. #endif    MPW
  347.     }
  348.     else
  349.         do_o_forks();
  350. }
  351.  
  352. /* write out .info file from information in the mh structure */
  353. forge_info()
  354. {
  355.     static char buf[DATABYTES];
  356. #ifndef    MPW
  357.     char *np;
  358.     FILE *fp;
  359.     int n;
  360.     long tdiff;
  361.     struct tm *tp;
  362. #ifdef BSD
  363.     struct timeb tbuf;
  364. #else
  365.     long bs;
  366. #endif
  367.     for (np = mh.m_name; *np; np++)
  368.         if (*np == '_') *np = ' ';
  369.  
  370.     buf[H_NLENOFF] = n = np - mh.m_name;
  371.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  372.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  373.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  374.     put2(buf + H_FLAGOFF, mh.m_flags & ~F_LOCKED);
  375.     if (pre_beta) {
  376.         put4(buf + H_OLD_DLENOFF, mh.m_datalen);
  377.         put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
  378.     }
  379.     else {
  380.         put4(buf + H_DLENOFF, mh.m_datalen);
  381.         put4(buf + H_RLENOFF, mh.m_rsrclen);
  382.  
  383.         /* convert unix file time to mac time format */
  384. #ifdef BSD
  385.         ftime(&tbuf);
  386.         tp = localtime(&tbuf.time);
  387.         tdiff = TIMEDIFF - tbuf.timezone * 60;
  388.         if (tp->tm_isdst)
  389.             tdiff += 60 * 60;
  390. #else
  391.         /* I hope this is right! -andy */
  392.         time(&bs);
  393.         tp = localtime(&bs);
  394.         tdiff = TIMEDIFF - timezone;
  395.         if (tp->tm_isdst)
  396.             tdiff += 60 * 60;
  397. #endif
  398.         put4(buf + H_CTIMOFF, mh.m_createtime + tdiff);
  399.         put4(buf + H_MTIMOFF, mh.m_modifytime + tdiff);
  400.     }
  401.     fp = fopen(files.f_info, "w");
  402.     if (fp == NULL) {
  403.         perror("info file");
  404.         exit(-1);
  405.     }
  406.     fwrite(buf, 1, DATABYTES, fp);
  407.     fclose(fp);
  408. #else    MPW
  409.     ParamBlockRec    pb;
  410.  
  411.     strcpy (buf, mh.m_name);
  412.     c2pstr (buf);
  413.     pb.fileParam.ioNamePtr = buf;
  414.     pb.fileParam.ioVRefNum = 0;
  415.     pb.fileParam.ioFVersNum = 0;
  416.     pb.fileParam.ioFDirIndex = 0;
  417.     pb.fileParam.ioResult = 0;
  418.     (void)PBGetFInfo (&pb, FALSE);
  419.     
  420.     pb.fileParam.ioFlFndrInfo.fdFlags = mh.m_flags;
  421. /*
  422.     pb.ioFlCrDat = mh.m_createtime;
  423.     pb.ioFlMdDat = mh.m_modifytime;
  424. */    
  425.     (void)PBSetFInfo (&pb, FALSE);
  426.     
  427. #endif    MPW
  428. }
  429.  
  430. /* eat characters until header detected, return which format */
  431. find_header()
  432. {
  433.     int c, at_bol;
  434.     char ibuf[BUFSIZ];
  435.  
  436.     /* look for "(This file ...)" line */
  437.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  438.         if (strncmp(ibuf, "(This file", 10) == 0)
  439.             break;
  440.     }
  441.     at_bol = 1;
  442.     while ((c = getc(ifp)) != EOF) {
  443.         switch (c) {
  444.         case '\n':
  445.         case '\r':
  446.             at_bol = 1;
  447.             break;
  448.         case ':':
  449.             if (at_bol)    /* q format */
  450.                 return 1;
  451.             break;
  452.         case '#':
  453.             if (at_bol) {    /* old format */
  454.                 ungetc(c, ifp);
  455.                 return 0;
  456.             }
  457.             break;
  458.         default:
  459.             at_bol = 0;
  460.             break;
  461.         }
  462.     }
  463.  
  464.     fprintf(stderr, "unexpected EOF\n");
  465.     exit(2);
  466.     /* NOTREACHED */
  467. }
  468.  
  469. static unsigned int crc;
  470.  
  471. short get2q();
  472. long get4q();
  473.  
  474. /* read header of .hqx file */
  475. do_q_header(macname)
  476. char *macname;
  477. {
  478.     char namebuf[256];        /* big enough for both att & bsd */
  479.     int n;
  480.     unsigned int calc_crc, file_crc;
  481.  
  482.     crc = 0;            /* compute a crc for the header */
  483.     q_init();            /* reset static variables */
  484.  
  485.     n = getq();            /* namelength */
  486.     n++;                /* must read trailing null also */
  487.     getqbuf(namebuf, n);        /* read name */
  488.     if (macname[0] == '\0')
  489.         macname = namebuf;
  490.  
  491.     n = strlen(macname);
  492.     if (n > NAMEBYTES)
  493.         n = NAMEBYTES;
  494.     strncpy(mh.m_name, macname, n);
  495.     mh.m_name[n] = '\0';
  496.  
  497.     getqbuf(mh.m_type, 4);
  498.     getqbuf(mh.m_author, 4);
  499.     mh.m_flags = get2q();
  500.     mh.m_datalen = get4q();
  501.     mh.m_rsrclen = get4q();
  502.  
  503.     comp_q_crc(0);
  504.     comp_q_crc(0);
  505.     calc_crc = crc;
  506.     file_crc = get2q();
  507.     /* no files no open at this point */
  508.     verify_crc(calc_crc, file_crc);
  509. }
  510.  
  511. do_q_fork(fname, len, dataFork)
  512. char *fname;
  513. register long len;
  514. Boolean dataFork;
  515. {
  516.     register int c, i;
  517.     unsigned int calc_crc, file_crc;
  518.  
  519. #ifdef    MPW
  520. #define    BSIZE 512
  521.     ParamBlockRec    pb;
  522.     register char    *p;
  523.     register int    count;
  524.     char            buf[BSIZE];
  525.     
  526.     c2pstr (fname);
  527.     pb.ioParam.ioCompletion = NULL;
  528.     pb.ioParam.ioNamePtr = fname;
  529.     pb.ioParam.ioVRefNum = 0;
  530.     pb.ioParam.ioVersNum = 0;
  531.     pb.ioParam.ioMisc = NULL;
  532.     pb.ioParam.ioPermssn = fsWrPerm;
  533.     
  534.     if (dataFork) {
  535.         if (PBOpen(&pb, FALSE) != noErr) {
  536.             fprintf(stderr, "trouble opening data fork\n");
  537.             exit (-1);
  538.         }
  539.     }
  540.     else {
  541.         if (PBOpenRF (&pb, FALSE) != noErr) {
  542.             fprintf(stderr, "trouble opening resource fork\n");
  543.             exit (-1);
  544.         }
  545.     }    
  546.     p2cstr (fname);
  547.     pb.ioParam.ioBuffer = &buf;
  548.     pb.ioParam.ioPosMode = fsAtMark;
  549.     pb.ioParam.ioPosOffset = 0L;
  550.     pb.ioParam.ioReqCount = BSIZE;
  551.     p = buf;
  552.     count = 0;
  553. #else    MPW
  554.     FILE *outf;
  555.  
  556.     outf = fopen(fname, "w");
  557.  
  558.     if (outf == NULL) {
  559.         perror(fname);
  560.         exit(-1);
  561.     }
  562. #endif    MPW
  563.  
  564.     crc = 0;    /* compute a crc for a fork */
  565.  
  566.     if (len)
  567.         for (i = 0; i < len; i++) {
  568.             if ((c = getq()) == EOF) {
  569.                 fprintf(stderr, "unexpected EOF\n");
  570.                 #ifdef    MPW
  571.                     PBClose(&pb, FALSE);
  572.                     FlushVol (NULL, 0);
  573.                 #else    MPW
  574.                     fclose(outf);
  575.                 #endif    MPW
  576.                 exit(2);
  577.             }
  578. #ifdef    MPW
  579.             *p++ = c;
  580.             count++;
  581.             if (count & 0x0F) SpinCursor(1);
  582.             if (count == BSIZE) {
  583.                 /* buffer full */
  584.                 (void) PBWrite (&pb, FALSE);
  585.                 count = 0;
  586.                 p = buf;
  587.             }
  588. #else    MPW                
  589.             putc(c, outf);
  590. #endif    MPW
  591.         }
  592.  
  593.     comp_q_crc(0);
  594.     comp_q_crc(0);
  595.     calc_crc = crc;
  596.     file_crc = get2q();
  597. #ifdef    MPW
  598.     if (count != 0) {
  599.         /* write out the last block */
  600.         SpinCursor(1);
  601.         pb.ioParam.ioReqCount = count;
  602.         (void) PBWrite (&pb, FALSE);
  603.     }
  604.     PBClose(&pb, FALSE);
  605.     FlushVol (NULL, 0);
  606. #else    MPW
  607.     fclose(outf);
  608. #endif    MPW
  609.     /* check CRC: we've written out a duff block but it doesn't matter */
  610.     verify_crc(calc_crc, file_crc);
  611. }
  612.  
  613. /* verify_crc(); -- check if crc's check out */
  614. verify_crc(calc_crc, file_crc)
  615. unsigned int calc_crc, file_crc;
  616. {
  617.     calc_crc &= WORDMASK;
  618.     file_crc &= WORDMASK;
  619.  
  620.     if (calc_crc != file_crc) {
  621.         fprintf(stderr, "CRC error\n---------\n");
  622.         fprintf(stderr, "CRC in file:\t0x%x\n", file_crc);
  623.         fprintf(stderr, "calculated CRC:\t0x%x\n", calc_crc);
  624.         exit(3);
  625.     }
  626. }
  627.  
  628. static int eof;
  629. static char obuf[3];
  630. static char *op, *oend;
  631.  
  632. /* initialize static variables for q format input */
  633. q_init()
  634. {
  635.     eof = 0;
  636.     op = obuf;
  637.     oend = obuf + sizeof obuf;
  638. }
  639.  
  640. /* get2q(); q format -- read 2 bytes from input, return short */
  641. short
  642. get2q()
  643. {
  644.     register int c;
  645.     short value = 0;
  646.  
  647.     c = getq();
  648.     value = (c & BYTEMASK) << 8;
  649.     c = getq();
  650.     value |= (c & BYTEMASK);
  651.  
  652.     return value;
  653. }
  654.  
  655. /* get4q(); q format -- read 4 bytes from input, return long */
  656. long
  657. get4q()
  658. {
  659.     register int c, i;
  660.     long value = 0L;
  661.  
  662.     for (i = 0; i < 4; i++) {
  663.         c = getq();
  664.         value <<= 8;
  665.         value |= (c & BYTEMASK);
  666.     }
  667.     return value;
  668. }
  669.  
  670. /* getqbuf(); q format -- read n characters from input into buf */
  671. /*        All or nothing -- no partial buffer allowed */
  672. getqbuf(buf, n)
  673. register char *buf;
  674. register int n;
  675. {
  676.     register int c, i;
  677.  
  678.     for (i = 0; i < n; i++) {
  679.         if ((c = getq()) == EOF)
  680.             return EOF;
  681.         *buf++ = c;
  682.     }
  683.     return 0;
  684. }
  685.  
  686. #define RUNCHAR 0x90
  687.  
  688. /* q format -- return one byte per call, keeping track of run codes */
  689. getq()
  690. {
  691.     register int c;
  692.  
  693.     if ((c = getq_nocrc()) == EOF)
  694.         return EOF;
  695.     comp_q_crc((unsigned)c);
  696.     return c;
  697. }
  698.  
  699. getq_nocrc()
  700. {
  701.     static int rep, lastc;
  702.     int c;
  703.  
  704.     if (rep) {
  705.         rep--;
  706.         return lastc;
  707.     }
  708.     if ((c = getq_raw()) == EOF) {
  709.         return EOF;
  710.     }
  711.     if (c == RUNCHAR) {
  712.         if ((rep = getq_raw()) == EOF)
  713.             return EOF;
  714.         if (rep != 0) {
  715.             /* already returned one, about to return another */
  716.             rep -= 2;
  717.             return lastc;
  718.         }
  719.         else {
  720.             lastc = RUNCHAR;
  721.             return RUNCHAR;
  722.         }
  723.     }
  724.     else {
  725.         lastc = c;
  726.         return c;
  727.     }
  728. }
  729.  
  730. /* q format -- return next 8 bits from file without interpreting run codes */
  731. getq_raw()
  732. {
  733.     char ibuf[4];
  734.     register char *ip = ibuf, *iend = ibuf + sizeof ibuf;
  735.     int c;
  736.  
  737.     if (op == obuf) {
  738.         for (ip = ibuf; ip < iend; ip++) {
  739.             if ((c = get6bits()) == EOF)
  740.                 if (ip <= &ibuf[1])
  741.                     return EOF;
  742.                 else if (ip == &ibuf[2])
  743.                     eof = 1;
  744.                 else
  745.                     eof = 2;
  746.             *ip = (char)(c & BYTEMASK);
  747.         }
  748.         obuf[0] = (ibuf[0] << 2 | ibuf[1] >> 4);
  749.         obuf[1] = (ibuf[1] << 4 | ibuf[2] >> 2);
  750.         obuf[2] = (ibuf[2] << 6 | ibuf[3]);
  751.     }
  752.     if ((eof) & (op >= &obuf[eof]))
  753.         return EOF;
  754.     /*
  755.     fprintf (stderr, "c = %c %02x\n",
  756.                      (*op > ' ')? (*op & BYTEMASK) :'.',
  757.                      *op & BYTEMASK);
  758.     */
  759.     c = *op++;
  760.     if (op >= oend)
  761.         op = obuf;
  762.     return (c & BYTEMASK);
  763. }
  764.  
  765. /*
  766. char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  767.              0 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
  768.              0                1               2               3 
  769. trlookup is used to translate by direct lookup.  The input character
  770. is an index into trlookup.  If the result is 0xFF, a bad char has been read.
  771. Added by:  Dan LaLiberte, liberte@uiucdcs.Uiuc.ARPA, ihnp4!uiucdcs!liberte
  772. */
  773. char trlookup[83] = {     0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  774.             0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF,
  775.             0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF,
  776.             0x14, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  777.             0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
  778.             0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0xFF,
  779.             0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0xFF,
  780.             0x2C, 0x2D, 0x2E, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
  781.             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF,
  782.             0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0xFF, 0xFF,
  783.             0x3D, 0x3E, 0x3F };
  784.  
  785. /* q format -- decode one byte into 6 bit binary */
  786. get6bits()
  787. {
  788.     register int c;
  789.     register int tc;
  790.  
  791.     while (1) {
  792.         c = getc(ifp) & BYTEMASK;
  793.         switch ((char)c) {
  794.         case '\n':
  795.         case '\r':
  796.             continue;
  797.         case ':':
  798.         case EOF:
  799.             return EOF;
  800.         default:
  801.             tc = c - (int)' ';
  802.              tc = (tc < 83) ? trlookup[tc] : 0xff;
  803. /*            fprintf(stderr, "c = '%c' %02x tc = %4x\n", c, c, tc);*/
  804.             if (tc != 0xff)
  805.                 return (tc);
  806.             fprintf(stderr, "bad char: '%c'\n", c);
  807.             return EOF;
  808.         }
  809.     }
  810. }
  811.  
  812.  
  813. #define CRCCONSTANT 0x1021
  814.  
  815. comp_q_crc(c)
  816. register unsigned int c;
  817. {
  818.     register int i;
  819.     register unsigned long temp = crc;
  820.  
  821.     for (i=0; i<8; i++) {
  822.         c <<= 1;
  823.         if ((temp <<= 1) & WORDBIT)
  824.             temp = (temp & WORDMASK) ^ CRCCONSTANT;
  825.         temp ^= (c >> 8);
  826.         c &= BYTEMASK;
  827.     }
  828.     crc = temp;
  829. }
  830.  
  831. /* old format -- process .hex and .hcx files */
  832. do_o_header(macname, filename)
  833. char *macname, *filename;
  834. {
  835.     char namebuf[256];        /* big enough for both att & bsd */
  836.     char ibuf[BUFSIZ];
  837.     int n;
  838.  
  839.     /* set up name for output files */
  840.     if (macname[0] == '\0') {
  841.         strcpy(namebuf, filename);
  842.  
  843.         /* strip directories */
  844.         macname = search_last(namebuf, '/');
  845.         if (macname == NULL)
  846.             macname = namebuf;
  847.         else
  848.             macname++;
  849.  
  850.         /* strip extension */
  851.         n = strlen(macname);
  852.         if (n > 4) {
  853.             n -= 4;
  854.             if (macname[n] == '.' && macname[n+1] == 'h'
  855.                         && macname[n+3] == 'x')
  856.                 macname[n] = '\0';
  857.         }
  858.     }
  859.     n = strlen(macname);
  860.     if (n > NAMEBYTES)
  861.         n = NAMEBYTES;
  862.     strncpy(mh.m_name, macname, n);
  863.     mh.m_name[n] = '\0';
  864.  
  865.     /* read "#TYPEAUTH$flag"  line */
  866.     if (fgets(ibuf, BUFSIZ, ifp) == NULL) {
  867.         fprintf(stderr, "unexpected EOF\n");
  868.         exit(2);
  869.     }
  870.     n = strlen(ibuf);
  871.     if (n >= 7 && ibuf[0] == '#' && ibuf[n-6] == '$') {
  872.         if (n >= 11)
  873.             strncpy(mh.m_type, &ibuf[1], 4);
  874.         if (n >= 15)
  875.             strncpy(mh.m_author, &ibuf[5], 4);
  876.         sscanf(&ibuf[n-5], "%4hx", &mh.m_flags);
  877.     }
  878. }
  879.  
  880. do_o_forks()
  881. {
  882.     char ibuf[BUFSIZ];
  883.     int forks = 0, found_crc = 0;
  884.     unsigned int calc_crc, file_crc;
  885.     extern long make_file();
  886. #ifdef    MPW
  887.     OSType    f_creator, f_type;
  888. #endif    MPW
  889.  
  890.  
  891.     crc = 0;    /* calculate a crc for both forks */
  892. #ifndef    MPW
  893.     /* create empty files ahead of time */
  894.     close(creat(files.f_data, 0666));
  895.     close(creat(files.f_rsrc, 0666));
  896. #else    MPW
  897.     BlockMove (mh.m_author, (char *)&f_creator, 4);
  898.     BlockMove (mh.m_type, (char *)&f_type, 4);
  899.     (void)Create (mh.m_name, 0, f_creator, f_type);
  900. #endif    MPW
  901.  
  902.     while (!found_crc && fgets(ibuf, BUFSIZ, ifp) != NULL) {
  903.         if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) {
  904.             compressed++;
  905.             continue;
  906.         }
  907.         if (strncmp(ibuf, "***DATA", 7) == 0) {
  908.             mh.m_datalen = make_file(files.f_data, compressed);
  909.             forks++;
  910.             continue;
  911.         }
  912.         if (strncmp(ibuf, "***RESOURCE", 11) == 0) {
  913.             mh.m_rsrclen = make_file(files.f_rsrc, compressed);
  914.             forks++;
  915.             continue;
  916.         }
  917.         if (compressed && strncmp(ibuf, "***CRC:", 7) == 0) {
  918.             found_crc++;
  919.             calc_crc = crc;
  920.             sscanf(&ibuf[7], "%x", &file_crc);
  921.             break;
  922.         }
  923.         if (!compressed && strncmp(ibuf, "***CHECKSUM:", 12) == 0) {
  924.             found_crc++;
  925.             calc_crc = crc & BYTEMASK;
  926.             sscanf(&ibuf[12], "%x", &file_crc);
  927.             file_crc &= BYTEMASK;
  928.             break;
  929.         }
  930.     }
  931.  
  932.     if (found_crc)
  933.         verify_crc(calc_crc, file_crc);
  934.     else {
  935.         fprintf(stderr, "missing CRC\n");
  936.         exit(3);
  937.     }
  938. }
  939.  
  940. long
  941. make_file(fname, compressed)
  942. char *fname;
  943. int compressed;
  944. {
  945.     char ibuf[BUFSIZ];
  946.     FILE *outf;
  947.     register long nbytes = 0L;
  948.  
  949.     outf = fopen(fname, "w");
  950.     if (outf == NULL) {
  951.         perror(fname);
  952.         exit(-1);
  953.     }
  954.  
  955.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  956.         if (strncmp(ibuf, "***END", 6) == 0)
  957.             break;
  958.         if (compressed)
  959.             nbytes += comp_to_bin(ibuf, outf);
  960.         else
  961.             nbytes += hex_to_bin(ibuf, outf);
  962.     }
  963.  
  964.     fclose(outf);
  965.     return nbytes;
  966. }
  967.  
  968. comp_c_crc(c)
  969. unsigned char c;
  970. {
  971.     crc = (crc + c) & WORDMASK;
  972.     crc = ((crc << 3) & WORDMASK) | (crc >> 13);
  973. }
  974.  
  975. comp_e_crc(c)
  976. unsigned char c;
  977. {
  978.     crc += c;
  979. }
  980.  
  981. #define SIXB(c) (((c)-0x20) & 0x3f)
  982.  
  983. comp_to_bin(ibuf, outf)
  984. char ibuf[];
  985. FILE *outf;
  986. {
  987.     char obuf[BUFSIZ];
  988.     register char *ip = ibuf;
  989.     register char *op = obuf;
  990.     register int n, outcount;
  991.     int numread, incount;
  992.  
  993.     numread = strlen(ibuf);
  994.     ip[numread-1] = ' ';        /* zap out the newline */
  995.     outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4);
  996.     incount = ((outcount / 3) + 1) * 4;
  997.     for (n = numread; n < incount; n++)    /* restore lost spaces */
  998.         ibuf[n] = ' ';
  999.  
  1000.     n = 0;
  1001.     while (n <= outcount) {
  1002.         *op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4;
  1003.         *op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2;
  1004.         *op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]);
  1005.         ip += 4;
  1006.         n += 3;
  1007.     }
  1008.  
  1009.     for (n=1; n <= outcount; n++)
  1010.         comp_c_crc((unsigned)obuf[n]);
  1011.  
  1012.     fwrite(obuf+1, 1, outcount, outf);
  1013.     return outcount;
  1014. }
  1015.  
  1016. hex_to_bin(ibuf, outf)
  1017. char ibuf[];
  1018. FILE *outf;
  1019. {
  1020.     register char *ip = ibuf;
  1021.     register int n, outcount;
  1022.     int c;
  1023.  
  1024.     n = strlen(ibuf) - 1;
  1025.     outcount = n / 2;
  1026.     for (n = 0; n < outcount; n++) {
  1027.         c = hexit(*ip++);
  1028.         comp_e_crc((unsigned)(c = (c << 4) | hexit(*ip++)));
  1029.         fputc(c, outf);
  1030.     }
  1031.     return outcount;
  1032. }
  1033.  
  1034. hexit(c)
  1035. int c;
  1036. {
  1037.     if ('0' <= c && c <= '9')
  1038.         return c - '0';
  1039.     if ('A' <= c && c <= 'F')
  1040.         return c - 'A' + 10;
  1041.  
  1042.     fprintf(stderr, "illegal hex digit: %c", c);
  1043.     exit(4);
  1044.     /* NOTREACHED */
  1045. }
  1046.  
  1047. put2(bp, value)
  1048. char *bp;
  1049. short value;
  1050. {
  1051.     *bp++ = (value >> 8) & BYTEMASK;
  1052.     *bp++ = value & BYTEMASK;
  1053. }
  1054.  
  1055. put4(bp, value)
  1056. char *bp;
  1057. long value;
  1058. {
  1059.     register int i, c;
  1060.  
  1061.     for (i = 0; i < 4; i++) {
  1062.         c = (value >> 24) & BYTEMASK;
  1063.         value <<= 8;
  1064.         *bp++ = c;
  1065.     }
  1066. }
  1067.